#pragma once;

#include "common.h"

#include "particle.h"
#include "force_generators.h"
#include "grid.h"

#include "shapes3d.h"

#include <string>
#include <sstream>


class PerfTiming
{
public:
	std::string name;
	double timeMillis;

	PerfTiming(std::string nom, double tim)
	{
		this->name = nom;
		this->timeMillis = tim;
	}

	std::string toString()
	{
		std::ostringstream ost;
		ost << "id = " << name << " timeMillis = " << timeMillis * 1000.0;
		return ost.str();
	}
};

class World
{
private:
	struct ForceRegistration
	{
		IForceGenerator *fgen;
		SpringBody *body;
	};

	struct CollisionInfo
	{
		Particle *particle;
		Edge *edge;
		Vec2f normal;
		real depth;
	};

	// Move particles
	void updateVerlet();
	// apply spring constraints and check for collision x times per update
	void iterateCollisions();
	// apply spring constraints
	void updateEdges();
	// test each object against each other
	void testCollision();
	// detect and store collision info if any
	bool detectCollision2( SpringBody * a, SpringBody * b );
	// test and resolve if needed
	void fineTest(SpringBody *bodyA, SpringBody *bodyB);
	// resolve a collision/collision response
	void processCollision();

public:
	World();
	void startFrame();
	void update(double dt);
	void draw();
	void debugDraw();
	void registerForceGenerator( IForceGenerator * fgen, SpringBody * body );
	// Check if a bounding box is doesn't contain any bodies. todo more acurate test? oriented bounds?
	bool isSpaceEmpty( BBox *bounds );
	bool isSpaceEmpty( real minx, real miny, real maxx, real maxy );
	// Creation
	SpringBody* createBody();
	Particle* createParticle( real x, real y );
	Edge* createEdge( Particle *p1, Particle *p2 );
	// Deletion
	void removeBody( SpringBody *body );
	// List of forces in world and bodies to apply them to
	std::vector< ForceRegistration > forceRegistry;
	std::vector< SpringBody* > bodyList;
	std::vector< Particle* > particlesList;
	std::vector< Edge* > edgeList;
	CollisionInfo collisionInfo;
	// List of hard collisions for sound
	std::vector< int > hardCollisions;
	// List of perf timings
	std::vector<PerfTiming> perfTimingList;
	void toggleGrid(){ useBruteforce = !useBruteforce; }

	Grid *myGrid;
	BBox worldBounds;
	bool useBruteforce;
};


void projectToAxis( SpringBody *body, const Vec2f &axis, real &min, real &max );